/**
 * Axios请求封装
 */
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { ElMessage, ElLoading } from 'element-plus'
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading'
import type { ApiResponse } from './types'

// 创建axios实例
const service: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: Number(import.meta.env.VITE_API_TIMEOUT) || 30000,
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
})

// loading实例
let loadingInstance: LoadingInstance | null = null
// 请求计数（用于控制loading显示）
let requestCount = 0

/**
 * 显示loading
 */
function showLoading() {
  if (requestCount === 0 && !loadingInstance) {
    loadingInstance = ElLoading.service({
      lock: true,
      text: '加载中...',
      background: 'rgba(0, 0, 0, 0.7)'
    })
  }
  requestCount++
}

/**
 * 隐藏loading
 */
function hideLoading() {
  requestCount--
  if (requestCount === 0 && loadingInstance) {
    loadingInstance.close()
    loadingInstance = null
  }
}

/**
 * 请求拦截器
 */
service.interceptors.request.use(
  (config: any) => {
    // 显示loading（可以通过配置控制是否显示）
    if (config.showLoading !== false) {
      showLoading()
    }

    return config
  },
  (error: AxiosError) => {
    hideLoading()
    console.error('请求错误:', error)
    return Promise.reject(error)
  }
)

/**
 * 响应拦截器
 */
service.interceptors.response.use(
  (response: AxiosResponse<ApiResponse>): any => {
    hideLoading()

    const { code, message } = response.data

    // 成功响应
    if (code === 200) {
      return response.data
    }

    // 错误响应处理
    switch (code) {
      case 403:
        // 无权限
        ElMessage.error(message || '无权限访问')
        break
      case 404:
        // 资源不存在
        ElMessage.error(message || '请求的资源不存在')
        break
      case 500:
        // 服务器错误
        ElMessage.error(message || '服务器错误')
        break
      default:
        // 其他错误
        ElMessage.error(message || '请求失败')
    }

    return Promise.reject(new Error(message || '请求失败'))
  },
  (error: AxiosError) => {
    hideLoading()

    console.error('响应错误:', error)

    // 网络错误
    if (!error.response) {
      ElMessage.error('网络连接失败，请检查网络')
      return Promise.reject(error)
    }

    // HTTP错误
    const { status } = error.response
    switch (status) {
      case 403:
        ElMessage.error('无权限访问')
        break
      case 404:
        ElMessage.error('请求的资源不存在')
        break
      case 500:
        ElMessage.error('服务器错误')
        break
      default:
        ElMessage.error('请求失败')
    }

    return Promise.reject(error)
  }
)

/**
 * 请求配置扩展（可以设置是否显示loading等）
 */
export interface RequestConfig extends AxiosRequestConfig {
  showLoading?: boolean
}

/**
 * 封装请求方法
 */
class Request {
  /**
   * GET请求
   */
  get<T = any>(url: string, params?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
    return service.get(url, { params, ...config })
  }

  /**
   * POST请求
   */
  post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
    return service.post(url, data, config)
  }

  /**
   * PUT请求
   */
  put<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
    return service.put(url, data, config)
  }

  /**
   * DELETE请求
   */
  delete<T = any>(url: string, params?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
    return service.delete(url, { params, ...config })
  }

  /**
   * 上传文件
   */
  upload<T = any>(url: string, file: File, config?: RequestConfig): Promise<ApiResponse<T>> {
    const formData = new FormData()
    formData.append('file', file)
    return service.post(url, formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      ...config
    })
  }

  /**
   * 下载文件
   */
  download(url: string, params?: any, filename?: string): Promise<void> {
    return service
      .get(url, {
        params,
        responseType: 'blob'
      })
      .then((response: any) => {
        const blob = new Blob([response])
        const link = document.createElement('a')
        link.href = window.URL.createObjectURL(blob)
        link.download = filename || '下载文件'
        link.click()
        window.URL.revokeObjectURL(link.href)
      })
  }
}

export default new Request()
